package sg.edu.nus.iss.ooad.jass.dao.file;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Properties;
import java.util.logging.Logger;
import sg.edu.nus.iss.ooad.jass.dao.IJobAdvertisementDAO;
import sg.edu.nus.iss.ooad.jass.entity.Advertiser;
import sg.edu.nus.iss.ooad.jass.entity.Company;
import sg.edu.nus.iss.ooad.jass.entity.IJASSEntity;
import sg.edu.nus.iss.ooad.jass.entity.JobAdvertisement;

/**
 *
 * JobAdvertisement Data Access Object for Properties File implementation.
 *
 * @author Isak Rabin (HT082193M)
 * @version 1.0
 * @since 1.0
 *
 * Development Environment : Netbeans IDE v6.7
 * Name of the File        : JobAdvertisementDAOPropertiesImpl.java
 * Creation / Modification History
 *         Isak Rabin        20-Sep-2009        Created
 *
 */
public class JobAdvertisementDAOPropertiesImpl extends AbstractPropertiesDAO implements IJobAdvertisementDAO {

        //JobAdvertisements List
        public static Hashtable<String, IJASSEntity> jobadvertisementCache = new Hashtable<String, IJASSEntity>();
        //Logger
        private final static Logger logger = Logger.getLogger(JobAdvertisementDAOPropertiesImpl.class.getName());
        //Properties filename
        public static final String JOBADVERTISEMENT_FILE = "data.jobadvertisement.properties";
        //Variable to hold Properties for JobAdvertisement
        public static Properties properties = null;

        //Load at start-up
        static {
                logger.info("Start loading " + JOBADVERTISEMENT_FILE);
                properties = loadProperties(JOBADVERTISEMENT_FILE);
                if (properties != null) {
                        JobAdvertisement jobadvertisement = new JobAdvertisement();
                        jobadvertisementCache = jobadvertisement.fromJASSPropertiesFormat(properties);
                }
                logger.info("Finish loading " + JOBADVERTISEMENT_FILE);
        }

        /**
         * Constructor
         */
        public JobAdvertisementDAOPropertiesImpl() {
        }

        /**
         * Create new JobAdvertisement entity and store it to the persistent data.
         * @param jobadvertisement
         * @return
         */
        public synchronized boolean createJobAdvertisement(JobAdvertisement jobadvertisement) {

                boolean retValue = false;

                //get number to total record
                int iTotalRecord = 0;
                String sTotalRecord = properties.getProperty("NumOfItems");
                if (sTotalRecord != null) {
                        iTotalRecord = Integer.parseInt(sTotalRecord);
                }
                iTotalRecord = iTotalRecord + 1;
                jobadvertisement.setID(String.valueOf(iTotalRecord));

                //update properties
                //JOBADVERTISEMENT_ATTRIBUTES = {"ID", "AdvertiserID", "CompanyID", "StartDate", "FinishDate", "JobTitle", "JobDescription", "JobLocation", "JobStartDate", "CompanyDepartment", "TechnicalSkills", "ManagementSkills", "MinSalary", "MaxSalary", "Deleted", "Withdrawn"};
                properties.put("ID" + String.valueOf(iTotalRecord), jobadvertisement.getID());
                properties.put("AdvertiserID" + String.valueOf(iTotalRecord), jobadvertisement.getAdvertiserID());
                properties.put("CompanyID" + String.valueOf(iTotalRecord), jobadvertisement.getCompanyID());
                properties.put("StartDate" + String.valueOf(iTotalRecord), jobadvertisement.getStartDate());
                properties.put("FinishDate" + String.valueOf(iTotalRecord), jobadvertisement.getFinishDate());
                properties.put("JobTitle" + String.valueOf(iTotalRecord), jobadvertisement.getJobTitle());
                properties.put("JobDescription" + String.valueOf(iTotalRecord), jobadvertisement.getJobDescription());
                properties.put("JobLocation" + String.valueOf(iTotalRecord), jobadvertisement.getJobLocation());
                properties.put("JobStartDate" + String.valueOf(iTotalRecord), jobadvertisement.getJobStartDate());
                properties.put("CompanyDepartment" + String.valueOf(iTotalRecord), jobadvertisement.getCompanyDepartment());
                properties.put("TechnicalSkills" + String.valueOf(iTotalRecord), jobadvertisement.getTechnicalSkills());
                properties.put("ManagementSkills" + String.valueOf(iTotalRecord), jobadvertisement.getManagementSkills());
                properties.put("MinSalary" + String.valueOf(iTotalRecord), String.valueOf(jobadvertisement.getMinSalary()));
                properties.put("MaxSalary" + String.valueOf(iTotalRecord), String.valueOf(jobadvertisement.getMaxSalary()));
                properties.put("Deleted" + String.valueOf(iTotalRecord), jobadvertisement.getDeleted());
                properties.put("Withdrawn" + String.valueOf(iTotalRecord), jobadvertisement.getWithdrawn());
                properties.setProperty("NumOfItems", String.valueOf(iTotalRecord));

                //save it and update the cache
                retValue = storeProperties(properties, JOBADVERTISEMENT_FILE);
                jobadvertisementCache.put(jobadvertisement.getID(), jobadvertisement);

                //cascase update
                //company -- advertisement
                Company company = (Company) CompanyDAOPropertiesImpl.companyCache.get(jobadvertisement.getCompanyID());
                company.getJobAdvertisement().add(jobadvertisement);
                //advertiser -- advertisement
                Advertiser advertiser = (Advertiser) AdvertiserDAOPropertiesImpl.advertiserCache.get(jobadvertisement.getAdvertiserID());
                advertiser.getJobAdvertisement().add(jobadvertisement);

                return retValue;
        }

        /**
         * Retrieve an JobAdvertisement from persistent data.
         * @param ID
         * @return
         */
        public JobAdvertisement retrieveJobAdvertisement(String ID) {
                JobAdvertisement retValue = null;

                retValue = (JobAdvertisement) jobadvertisementCache.get(ID);

                return retValue;
        }

        /**
         * Update JobAdvertisement from persistent data.
         * @param jobadvertisement
         * @return
         */
        public synchronized boolean updateJobAdvertisement(JobAdvertisement jobadvertisement) {
                boolean retValue = false;

                if (jobadvertisementCache.containsKey(jobadvertisement.getID())) {

                        //update properties
                        //JOBADVERTISEMENT_ATTRIBUTES = {"ID", "AdvertiserID", "CompanyID", "StartDate", "FinishDate", "JobTitle", "JobDescription", "JobLocation", "JobStartDate", "CompanyDepartment", "TechnicalSkills", "ManagementSkills", "MinSalary", "MaxSalary", "Deleted", "Withdrawn"};
                        properties.setProperty("AdvertiserID" + jobadvertisement.getID(), jobadvertisement.getAdvertiserID());
                        properties.setProperty("CompanyID" + jobadvertisement.getID(), jobadvertisement.getCompanyID());
                        properties.setProperty("StartDate" + jobadvertisement.getID(), jobadvertisement.getStartDate());
                        properties.setProperty("FinishDate" + jobadvertisement.getID(), jobadvertisement.getFinishDate());
                        properties.setProperty("JobTitle" + jobadvertisement.getID(), jobadvertisement.getJobTitle());
                        properties.setProperty("JobDescription" + jobadvertisement.getID(), jobadvertisement.getJobDescription());
                        properties.setProperty("JobLocation" + jobadvertisement.getID(), jobadvertisement.getJobLocation());
                        properties.setProperty("JobStartDate" + jobadvertisement.getID(), jobadvertisement.getJobStartDate());
                        properties.setProperty("CompanyDepartment" + jobadvertisement.getID(), jobadvertisement.getCompanyDepartment());
                        properties.setProperty("TechnicalSkills" + jobadvertisement.getID(), jobadvertisement.getTechnicalSkills());
                        properties.setProperty("ManagementSkills" + jobadvertisement.getID(), jobadvertisement.getManagementSkills());
                        properties.setProperty("MinSalary" + jobadvertisement.getID(), String.valueOf(jobadvertisement.getMinSalary()));
                        properties.setProperty("MaxSalary" + jobadvertisement.getID(), String.valueOf(jobadvertisement.getMaxSalary()));
                        properties.setProperty("Deleted" + jobadvertisement.getID(), jobadvertisement.getDeleted());
                        properties.setProperty("Withdrawn" + jobadvertisement.getID(), jobadvertisement.getWithdrawn());

                        //save it  and update the cache
                        storeProperties(properties, JOBADVERTISEMENT_FILE);
                        jobadvertisementCache.remove(jobadvertisement.getID());
                        jobadvertisementCache.put(jobadvertisement.getID(), jobadvertisement);

                        //cascase update
                        //company -- advertisement
                        Company company = (Company) CompanyDAOPropertiesImpl.companyCache.get(jobadvertisement.getCompanyID());
                        for (Iterator<JobAdvertisement> i = company.getJobAdvertisement().iterator(); i.hasNext();) {
                                JobAdvertisement dataObject = i.next();
                                if (dataObject.getID().equalsIgnoreCase(jobadvertisement.getID())) {
                                        i.remove();
                                } else {
                                        continue;
                                }
                        }
                        company.getJobAdvertisement().add(jobadvertisement);

                        //advertiser -- advertisement
                        Advertiser advertiser = (Advertiser) AdvertiserDAOPropertiesImpl.advertiserCache.get(jobadvertisement.getAdvertiserID());
                        advertiser.getJobAdvertisement().add(jobadvertisement);
                        for (Iterator<JobAdvertisement> i = company.getJobAdvertisement().iterator(); i.hasNext();) {
                                JobAdvertisement dataObject = i.next();
                                if (dataObject.getID().equalsIgnoreCase(jobadvertisement.getID())) {
                                        i.remove();
                                } else {
                                        continue;
                                }
                        }
                        advertiser.getJobAdvertisement().add(jobadvertisement);

                        //return value
                        retValue = true;
                }


                return retValue;
        }

        /**
         * Mark JobAdvertisement as deleted.
         * @param jobadvertisement
         * @return
         */
        public boolean deleteJobAdvertisement(JobAdvertisement jobadvertisement) {
                boolean retValue = false;

                if (jobadvertisementCache.containsKey(jobadvertisement.getID())) {

                        //update properties
                        jobadvertisement.setDeleted(new Date(System.currentTimeMillis()).toString());
                        jobadvertisementCache.remove(jobadvertisement.getID());
                        properties.setProperty("Deleted" + jobadvertisement.getID(), jobadvertisement.getDeleted());
                        jobadvertisementCache.put(jobadvertisement.getID(), jobadvertisement);

                        //cascase update
                        //company -- advertisement
                        Company company = (Company) CompanyDAOPropertiesImpl.companyCache.get(jobadvertisement.getCompanyID());
                        for (Iterator<JobAdvertisement> i = company.getJobAdvertisement().iterator(); i.hasNext();) {
                                JobAdvertisement dataObject = i.next();
                                if (dataObject.getID().equalsIgnoreCase(jobadvertisement.getID())) {
                                        i.remove();
                                } else {
                                        continue;
                                }
                        }
                        company.getJobAdvertisement().add(jobadvertisement);

                        //advertiser -- advertisement
                        Advertiser advertiser = (Advertiser) AdvertiserDAOPropertiesImpl.advertiserCache.get(jobadvertisement.getAdvertiserID());
                        advertiser.getJobAdvertisement().add(jobadvertisement);
                        for (Iterator<JobAdvertisement> i = company.getJobAdvertisement().iterator(); i.hasNext();) {
                                JobAdvertisement dataObject = i.next();
                                if (dataObject.getID().equalsIgnoreCase(jobadvertisement.getID())) {
                                        i.remove();
                                } else {
                                        continue;
                                }
                        }
                        advertiser.getJobAdvertisement().add(jobadvertisement);


                        retValue = true;
                }

                return retValue;
        }

        /**
         * Retrieve all JobAdvertisement from persistent data
         * @return List of JobAdvertisement
         */
        public List<JobAdvertisement> getAllJobAdvertisement() {
                List<JobAdvertisement> retValue = new ArrayList<JobAdvertisement>();

                //Looping the whole records from cache
                Enumeration elements = jobadvertisementCache.elements();
                while (elements.hasMoreElements()) {
                        JobAdvertisement jobadvertisement = (JobAdvertisement) elements.nextElement();
                        if (!(jobadvertisement.isDeleted() || jobadvertisement.isWithdrawn())) {
                                retValue.add(jobadvertisement);
                        }
                }

                return retValue;
        }

        /**
         * Find JobAdvertisement from persistent data by using Job Advertisement Title as search criteria.
         * @param title JobAdvertisement Title
         * @return List of JobAdvertisement
         */
        public List<JobAdvertisement> findJobAdvertisementByTitle(String advertiserID, String title) {
                List<JobAdvertisement> retValue = new ArrayList<JobAdvertisement>();

                Enumeration<IJASSEntity> elements = jobadvertisementCache.elements();
                while (elements.hasMoreElements()) {
                        JobAdvertisement jobadvertisement = (JobAdvertisement) elements.nextElement();
                        if (title.toLowerCase().matches(jobadvertisement.getJobTitle().toLowerCase())) {
                                if ("".equalsIgnoreCase(advertiserID)) {
                                        if (!(jobadvertisement.isDeleted() || jobadvertisement.isWithdrawn())) {
                                                retValue.add(jobadvertisement);
                                        }
                                } else if (advertiserID.equalsIgnoreCase(jobadvertisement.getAdvertiserID())) {
                                        if (!jobadvertisement.isDeleted()) {
                                                retValue.add(jobadvertisement);
                                        }
                                }
                        }
                }

                return retValue;
        }

        /**
         * Find JobAdvertisement from persistent data by using Job Advertisement Location as search criteria.
         * @param location JobAdvertisement Location
         * @return List of JobAdvertisement
         */
        public List<JobAdvertisement> findJobAdvertisementByLocation(String advertiserID, String location) {
                List<JobAdvertisement> retValue = new ArrayList<JobAdvertisement>();

                Enumeration<IJASSEntity> elements = jobadvertisementCache.elements();
                while (elements.hasMoreElements()) {
                        JobAdvertisement jobadvertisement = (JobAdvertisement) elements.nextElement();
                        if (location.toLowerCase().matches(jobadvertisement.getJobLocation().toLowerCase())) {
                                if ("".equalsIgnoreCase(advertiserID)) {
                                        if (!(jobadvertisement.isDeleted() || jobadvertisement.isWithdrawn())) {
                                                retValue.add(jobadvertisement);
                                        }
                                } else if (advertiserID.equalsIgnoreCase(jobadvertisement.getAdvertiserID())) {
                                        if (!jobadvertisement.isDeleted()) {
                                                retValue.add(jobadvertisement);
                                        }
                                }
                        }
                }

                return retValue;
        }

        /**
         * Find JobAdvertisement by using JobAdvertisement Technical/Management Skills as search criteria
         * @param skills JobAdvertisement Technical/Management Skills.
         * @return List of JobAdvertisement.
         */
        public List<JobAdvertisement> findJobAdvertisementBySkills(String advertiserID, String skills) {
                List<JobAdvertisement> retValue = new ArrayList<JobAdvertisement>();

                Enumeration<IJASSEntity> elements = jobadvertisementCache.elements();
                while (elements.hasMoreElements()) {
                        JobAdvertisement jobadvertisement = (JobAdvertisement) elements.nextElement();
                        if (((jobadvertisement.getTechnicalSkills().toLowerCase().indexOf(skills.toLowerCase()) != -1) ||
                                (jobadvertisement.getManagementSkills().toLowerCase().indexOf(skills.toLowerCase()) != -1))) {
                                if ("".equalsIgnoreCase(advertiserID)) {
                                        if (!(jobadvertisement.isDeleted() || jobadvertisement.isWithdrawn())) {
                                                retValue.add(jobadvertisement);
                                        }
                                } else if (advertiserID.equalsIgnoreCase(jobadvertisement.getAdvertiserID())) {
                                        if (!jobadvertisement.isDeleted()) {
                                                retValue.add(jobadvertisement);
                                        }
                                }
                        }
                }

                return retValue;
        }

        /**
         * Find JobAdvertisement for the "n" days as search criteria
         * @param nDaysBefore The number of days.
         * @return List of JobAdvertisement for the last n days.
         */
        public List<JobAdvertisement> findJobAdvertisementByAdvertisementDate(String advertiserID, int nDaysBefore) {
                List<JobAdvertisement> retValue = new ArrayList<JobAdvertisement>();

                SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy");

                Date jobadvertisementStartDate = null;
                Calendar currentCalendar = Calendar.getInstance();
                Calendar jobadvertisementCalendar = Calendar.getInstance();

                currentCalendar.setTime(new Date(System.currentTimeMillis()));
                jobadvertisementCalendar.setTime(new Date(System.currentTimeMillis()));

                Enumeration<IJASSEntity> elements = jobadvertisementCache.elements();
                while (elements.hasMoreElements()) {
                        JobAdvertisement jobadvertisement = (JobAdvertisement) elements.nextElement();
                        try {
                                //parse the startDate parameter
                                jobadvertisementCalendar.setLenient(false);
                                jobadvertisementStartDate = dateFormat.parse(jobadvertisement.getStartDate());
                                jobadvertisementCalendar.setTime(jobadvertisementStartDate);

                                currentCalendar.add(Calendar.DATE, (-1 * nDaysBefore));
                                if (jobadvertisementCalendar.after(currentCalendar)) {
                                        if ("".equalsIgnoreCase(advertiserID)) {
                                                if (!(jobadvertisement.isDeleted() || jobadvertisement.isWithdrawn())) {
                                                        retValue.add(jobadvertisement);
                                                }
                                        } else if (advertiserID.equalsIgnoreCase(jobadvertisement.getAdvertiserID())) {
                                                if (!jobadvertisement.isDeleted()) {
                                                        retValue.add(jobadvertisement);
                                                }
                                        }
                                }
                        } catch (ParseException pe) {
                                pe.printStackTrace();
                        }

                }

                return retValue;
        }

        /**
         * Find JobAdvertisement from persistent data by using Job Advertisement Salary as search criteria.
         * @param salary Job Advertisement Salary
         * @return List of JobAdvertisement
         */
        public List<JobAdvertisement> findJobAdvertisementBySalary(String advertiserID, float salary) {
                List<JobAdvertisement> retValue = new ArrayList<JobAdvertisement>();

                Enumeration<IJASSEntity> elements = jobadvertisementCache.elements();
                while (elements.hasMoreElements()) {
                        JobAdvertisement jobadvertisement = (JobAdvertisement) elements.nextElement();
                        boolean matches = (jobadvertisement.getMinSalary() >= salary);
                        if (matches) {
                                if ("".equalsIgnoreCase(advertiserID)) {
                                        if (!(jobadvertisement.isDeleted() || jobadvertisement.isWithdrawn())) {
                                                retValue.add(jobadvertisement);
                                        }
                                } else if (advertiserID.equalsIgnoreCase(jobadvertisement.getAdvertiserID())) {
                                        if (!jobadvertisement.isDeleted()) {
                                                retValue.add(jobadvertisement);
                                        }
                                }
                        }
                }

                return retValue;
        }

        /**
         * Find JobAdvertisement from persistent data by using Job Advertisement Company ID as search criteria.
         * @param companyID Company ID
         * @return List of JobAdvertisement
         */
        public List<JobAdvertisement> findJobAdvertisementByCompanyId(String advertiserID, String companyID) {
                List<JobAdvertisement> retValue = new ArrayList<JobAdvertisement>();

                Enumeration<IJASSEntity> elements = jobadvertisementCache.elements();
                while (elements.hasMoreElements()) {
                        JobAdvertisement jobadvertisement = (JobAdvertisement) elements.nextElement();
                        if (companyID.toLowerCase().matches(jobadvertisement.getCompanyID().toLowerCase())) {
                                if ("".equalsIgnoreCase(advertiserID)) {
                                        if (!(jobadvertisement.isDeleted() || jobadvertisement.isWithdrawn())) {
                                                retValue.add(jobadvertisement);
                                        }
                                } else if (advertiserID.equalsIgnoreCase(jobadvertisement.getAdvertiserID())) {
                                        if (!jobadvertisement.isDeleted()) {
                                                retValue.add(jobadvertisement);
                                        }
                                }
                        }
                }

                return retValue;
        }

        /**
         * Find JobAdvertisement from persistent data by using Job Advertisement Company Name as search criteria.
         * @param companyName Company Name
         * @return List of JobAdvertisement
         */
        public List<JobAdvertisement> findJobAdvertisementByCompanyName(String advertiserID, String companyName) {
                List<JobAdvertisement> retValue = new ArrayList<JobAdvertisement>();

                Enumeration<IJASSEntity> elements = CompanyDAOPropertiesImpl.companyCache.elements();
                while (elements.hasMoreElements()) {
                        Company company = (Company) elements.nextElement();
                        if (companyName.toLowerCase().matches(company.getName().toLowerCase())) {
                                for (Iterator<JobAdvertisement> i = company.getJobAdvertisement().iterator(); i.hasNext();) {
                                        JobAdvertisement jobadvertisement = i.next();
                                        if ("".equalsIgnoreCase(advertiserID)) {
                                                if (!(jobadvertisement.isDeleted() || jobadvertisement.isWithdrawn())) {
                                                        retValue.add(jobadvertisement);
                                                }
                                        } else if (advertiserID.equalsIgnoreCase(jobadvertisement.getAdvertiserID())) {
                                                if (!jobadvertisement.isDeleted()) {
                                                        retValue.add(jobadvertisement);
                                                }
                                        }

                                }
                        }
                }

                return retValue;
        }

        /**
         * Find JobAdvertisement from persistent data by using Job Advertisement Advertiser ID as search criteria.
         * @param AdvertiserID Advertiser ID
         * @return List of JobAdvertisement
         */
        public List<JobAdvertisement> findJobAdvertisementByAdvertiserID(String advertiserID) {
                ArrayList<JobAdvertisement> retValue = new ArrayList<JobAdvertisement>();
                Enumeration<IJASSEntity> elements = jobadvertisementCache.elements();
                while (elements.hasMoreElements()) {
                        JobAdvertisement jobadvertisement = (JobAdvertisement) elements.nextElement();
                        if (advertiserID.toLowerCase().matches(jobadvertisement.getAdvertiserID().toLowerCase())) {
                                if (!jobadvertisement.isDeleted()) {
                                        retValue.add(jobadvertisement);
                                }
                        }
                }
                return retValue;
        }

        /**
         * Find JobAdvertisement from persistent data by using Job Advertisement Advertiser Name as search criteria.
         * @param advertiserName Advertiser Name
         * @return List of JobAdvertisement
         */
        public List<JobAdvertisement> findJobAdvertisementByAdvertiserName(String advertiserName) {
                ArrayList<JobAdvertisement> retValue = new ArrayList<JobAdvertisement>();

                Enumeration<IJASSEntity> elements = AdvertiserDAOPropertiesImpl.advertiserCache.elements();
                while (elements.hasMoreElements()) {
                        Advertiser advertiser = (Advertiser) elements.nextElement();
                        if (advertiserName.toLowerCase().matches(advertiser.getName().toLowerCase())) {
                                for (Iterator<JobAdvertisement> i = advertiser.getJobAdvertisement().iterator(); i.hasNext();) {
                                        JobAdvertisement jobadvertisement = i.next();
                                        if (!jobadvertisement.isDeleted()) {
                                                retValue.add(jobadvertisement);
                                        }
                                }
                        }
                }

                return retValue;
        }

        /**
         * Return JobAdvertisement Cache
         * @return
         */
        public static synchronized Hashtable<String, IJASSEntity> cache() {
                return jobadvertisementCache;
        }
}
